package nape.space;
import cx.FastList;
import cx.Algorithm;
import cx.Allocator;
import nape.shape.Shape;
import nape.geom.Vec2;
import nape.geom.Ray;
import nape.geom.RayResult;
import nape.geom.VecMath;
import nape.phys.PhysObj;
import nape.space.Space;
import nape.dynamics.Collide;
import nape.Const;
import nape.Config;
import nape.util.FastMath;
import nape.callbacks.Callback;
























class BruteSpace extends Space {
	
	public var static_shapes :CxFastList(Shape);
	public var dynamic_shapes:CxFastList(Shape);
	
	
	
	public function new (?gravity:Vec2) {
		super(gravity);
		sleeping = false;
		
		static_shapes  = new CxFastList(Shape)();
		dynamic_shapes = new CxFastList(Shape)();
	}
	
	
	
	public override function addObject(o:PhysObj):Void {
		if(o.added_to_space) return;
		objects.add(o); o.added_to_space = true;
		add_aux(o);
		
		o.visible = o.pvisible = false;
		
		if (o.isBody) {
			var body = o.body;
			if (body.isStatic = (body.imass == 0 && body.imoment == 0)) {
				addStatic(body);
				body.updatePosition(0);
				CxIter(s,body.shapes,{
					static_shapes.add(s);
					s.updateShape();
				});
			}else {
				addDynamic(body);
				CxIterate(body.shapes,dynamic_shapes.add);
				addProperties(o.properties);
			}
			registerBody(body);
		}else {
			var part = o.particle;
			addParticle(part);
			registerBase(part);
			addProperties(o.properties);
		}
	}
	public override function removeObject(o:PhysObj):Void {
		if(objects.remove(o)) {
			rem_aux(o);
			
			o.added_to_space = false;
			if(o.pvisible || o.visible) {
				visible.remove(o);
				physobj_cb(o,Hide,HIDE);
			}
			o.visible = o.pvisible = false;
		
			if (o.isBody) {
				var body = o.body;
				if (body.isStatic) {
					removeStatic(body);
					CxIterate(body.shapes,static_shapes.remove);
				}else {
					removeDynamic(body);
					CxIterate(body.shapes,dynamic_shapes.remove);
					removeProperties(o.properties);
				}
			}else {
				var part = o.particle;
				removeParticle(part);
				removeProperties(o.properties);
			}
			removeConstraints(o);
		}
	}
	
	
	
	public override function broadphase():Void {
		CxIter(stat, static_shapes,{
			CxIter(dyn, dynamic_shapes, narrowPhase_SD(stat,dyn ));
			CxIter(part, particles,     narrowPhase_SP(stat,part));
		});
		CxIter(i,dynamic_shapes,{
			CxIterIte(j,dynamic_shapes,cxiterator.next, narrowPhase_DD(i,j));
			CxIter(part, particles, narrowPhase_DP(i,part));
		});
	}
	
	
	
	public override function objectAtPoint(x:Float,y:Float):PhysObj {
		var p = new Vec2(x,y);
		CxIter(b,dynamics,{
			if(collide.bodyContains(b.body,p))
				return b;
		});
		CxIter(s,statics,{
			if(collide.bodyContains(s.body,p))
				return s;
		});
		CxIter(t,particles,{
			if(collide.partContains(t,p))
				return t;
		});
		return null;
	}
	
	
	
	public override function rayCast(r:Ray):RayResult {
		var mint:Float = RayCast.FAIL;
		var mino:PhysObj = null;
		var mins:Shape = null;
		vec_new(polyn,0,0);
		var tempn:Vec2 = new Vec2();
		
		
		 CxIter(b,dynamics,{
			CxIter(s,b.shapes,{
				var t = if(s.type == Shape.CIRCLE) RayCast.rayCircle (r,s.circle );
				        else                       RayCast.rayPolygon(r,s.polygon,tempn);
				if(t<mint) {
					mint = t;
					mino = b;
					mins = s;
					vec_set(polyn,tempn.p);
				}
			});
		});
		 CxIter(b,statics,{
			CxIter(s,b.shapes,{
				var t = if(s.type == Shape.CIRCLE) RayCast.rayCircle (r,s.circle );
				        else                       RayCast.rayPolygon(r,s.polygon,tempn);
				if(t<mint) {
					mint = t;
					mino = b;
					mins = s;
					vec_set(polyn,tempn.p);
				}
			});
		});
		
		if(mint!=RayCast.FAIL) {
			var ret = new RayResult();
			ret.obj = mino;
			ret.shape = mins;
			vec_set(ret.p,r.a);
			vec_addeq(ret.p,r.v,mint);
			if(ret.shape.type == Shape.CIRCLE) {
				vec_sub(ret.p,ret.shape.circle.centre.p,ret.n);
				vec_normalise(ret.n);
			}else {
				vec_set(ret.n,polyn);
			}
			ret.t = mint;
			return ret;
		}else
			return null;
	}
	
	
	
	public override function visitate() {
		var vi = visible.begin();
		var pi = null;
		
		CxIter(o,objects,{
			if(o.aabb.intersect(viewport)) {
				if(!o.pvisible) {
					o.pvisible = true;
					visible.add(o);
					physobj_cb(o,Show,SHOW);
					if(pi==null) pi = visible.begin();
				}
				o.visible = true;
			}
		});
		
		
		CxIterIte(o,visible,vi,{
			if(!o.visible) {
				o.pvisible = false;
				physobj_cb(o,Hide,HIDE);
				cxiterator = visible.erase(pi,cxiterator);
				continue;
			}
			pi = cxiterator;
		});
	}
}